
<script>
  // function fn() {}
  // fn = () => {}
  
  // var user = (username, userId) => {username, userId}
  
  
  const user = {
    fullname: '乔布斯',
    sayHi(p) {
      console.log(this)
      console.log(`${this.fullname} 对 ${p} 说：Hi`)
    }
  }
  user.sayHi('侯广杰')
  
  const {sayHi} = user
  sayHi('侯广杰')
  
  const user2 = {
    fullname: '比尔盖茨'
  }
  user2.sayHi = sayHi
  user2.sayHi('侯广杰')
  
  const clazz = {
    name: '2107a',
    users: [{
      fullname: '马云',
      sayHi: sayHi
    }]
  }
  
  clazz.users[0].sayHi('aaa')
  
  let user4 = {fullname: '张三'}
  sayHi.apply(user4, ['某某'])
  sayHi.call(user4, '某某2')
  // user4.sayHi = sayHi
  // user4.sayHi('某某')
  
  user.sayHi.apply(user4, ['某某3'])
  
  /*
  function 声明的函数 this是跟随调用的上下文变化的（this是不固定的）
  
  ```
  obj1.obj2.fn()  // this是obj1.obj2
  // fn的this是.前面的所有对象
  ```
  
  ```
  fn.call(obj)/fn.apply(obj) // this是obj
  // 如果用apply/call去指定fn的this，
  //  fn会用指定的参数作为自己的this
  ```
  
  ````
  fn() // this是window
  // 如果调用方法没有上下文，也没有用apply/call，
  //  fn里的this会使用全局里顶级变量当成this（非严格模式）
  ```
  
  ```
  const fn2 = fn.bind(obj)
  // fn.bind(obj) 返回一个新的function
  // fn2里this是固定的，不变的，
  fn2() // this是obj
  fn2.call(obj2) // this还是obj
  user.fn2() // this还是obj
  const fn3 = fn2.bind(obj2) // fn3里的this仍然是obj
  ```
  */
  
  var name = '盖茨'
  
  var person = {
    name: '乔布斯',
    sayHi: function () {
      // 箭头函数它会自动绑定当前定义箭头函数环境内部的this值
      console.log(this)
      // const fn =  (function() {
      //   console.log('Hi, ' + this.name)
      // }).bind(this)
      // setTimeout(fn)
      setTimeout(() => {
        console.log('Hi, ' + this.name)
      })
    },
  }
  person.sayHi() // Hi, 盖茨
  
  person.sayHi.call({name: '马云'})
  
  var person4 = {
    name: '乔布斯',
    sayHi: () => {
      console.log(this.name)
    },
  }
  person4.sayHi()
  
  
  function fn4() {
    console.log(this)
    let obj = {
      a: 1,
      b: () => {console.log(this)}
    }
    obj.a = 1
    obj.b = () => console.log(this)
  }
  </script>